#ifndef __WIZ_DATATYPE_SMARTPTR_HPP__SHANHAOBO_19800429__
#define __WIZ_DATATYPE_SMARTPTR_HPP__SHANHAOBO_19800429__

#include "../../Base/WizBase.hpp"
#include "../../System/WizAtomicCount.hpp"

namespace Wiz
{
    namespace SmartPtr
    {
        template<class ElementT>
        class Type
        {
            typedef ElementT            tElement;
            typedef tElement*           tElementPtr;
            typedef tElement            tValue;
            typedef Type                tThis;
        public:
            explicit Type(tElementPtr p = WIZ_NULLPTR): m_Ptr(p)
            {
                m_ACPtr = ::Wiz::AtomicCount::Create();
                m_ACPtr->Increment();
            }

            ~Type()
            {
                if(m_ACPtr->DecIsZero())
                {
                    ::Wiz::SafeDelete(m_Ptr);
                    ::Wiz::AtomicCount::Destroy(m_ACPtr);
                }
            }

            Type(tThis const & r): m_Ptr(r.m_Ptr)  // never throws
            {
                m_ACPtr = r.m_ACPtr;
                m_ACPtr->Increment();
            }

            Type & operator=(tThis const & r)
            {
                Type(r).Swap(*this);
                return *this;
            }

            ::Wiz::Void::Type Reset(tElementPtr p = WIZ_NULLPTR)
            {
                WIZ_ASSERT(p == WIZ_NULLPTR || p != m_Ptr);
                Type(p).Swap(*this);
            }

            tElement& operator*() const  // never throws
            {
                WIZ_ASSERT(::Wiz::IsValidPtr(m_Ptr));
                return *m_Ptr;
            }

            tElementPtr operator->() const  // never throws
            {
                WIZ_ASSERT(::Wiz::IsValidPtr(m_Ptr));
                return m_Ptr;
            }

            tElementPtr Get() const
            {
                return m_Ptr;
            }

            ::Wiz::Void::Type Swap(tThis & Other)
            {
                ::Wiz::Swap(m_Ptr, Other.m_Ptr);
                ::Wiz::Swap(m_ACPtr, Other.m_ACPtr);
            }

        private:

            tElementPtr m_Ptr;
            ::Wiz::AtomicCount::Ptr m_ACPtr;
        }; /// Type
    } /// end of namespace SmartPtr
    template<class T, class U>
    WIZ_INLINE ::Wiz::Bool::Type operator==(::Wiz::SmartPtr::Type<T> const & a, ::Wiz::SmartPtr::Type<U> const & b)
    {
        return a.Get() == b.Get();
    }

    template<class T, class U>
    WIZ_INLINE ::Wiz::Bool::Type operator!=(::Wiz::SmartPtr::Type<T> const & a, ::Wiz::SmartPtr::Type<U> const & b)
    {
        return a.Get() != b.Get();
    }

    template<class T>
    WIZ_INLINE ::Wiz::Bool::Type operator<(::Wiz::SmartPtr::Type<T> const & a, ::Wiz::SmartPtr::Type<T> const & b)
    {
        return ::std::less<T*>()(a.Get(), b.Get());
    }

    template<class T>
    WIZ_INLINE ::Wiz::Void::Type Swap(::Wiz::SmartPtr::Type<T> & Lhs, ::Wiz::SmartPtr::Type<T> & b)
    {
        Lhs.Swap(b);
    }
} /// end of namespace Wiz

////////////////////////////////////////////////////////////////////////////////

#   define WIZ_DECLARE_SMARTPTR(t)                      \
    typedef ::Wiz::SmartPtr::Type<t>          SmartPtr;       \
    typedef const ::Wiz::SmartPtr::Type<t>&   InSmartPtr;     \
    typedef ::Wiz::SmartPtr::Type<t>&         OutSmartPtr;    \
    typedef ::Wiz::SmartPtr::Type<t>&         InOutSmartPtr;

////////////////////////////////////////////////////////////////////////////////

#endif /*__WIZ_DATATYPE_SMARTPTR_HPP__SHANHAOBO_19800429__*/
